#ifndef __M_ROOM_H__
#define __M_ROOM_H__
#include "util.hpp"
#include "logger.hpp"
#include "online.hpp"
#include "db.hpp"

// 常量定义（五子棋棋盘与棋子）
#define BOARD_ROW 15    // 棋盘行数
#define BOARD_COL 15    // 棋盘列数
#define CHESS_WHITE 1   // 白棋标识
#define CHESS_BLACK 2   // 黑棋标识

// 房间状态枚举
typedef enum {
    GAME_START,  // 游戏进行中
    GAME_OVER    // 游戏结束
} room_statu;

class room {
private:
    
    uint64_t _room_id;               
    room_statu _statu;               // 房间状态
    int _player_count;               // 玩家数量
    uint64_t _white_id;              // 白棋玩家ID
    uint64_t _black_id;              // 黑棋玩家ID
    user_table* _tb_user;            // 用户数据库操作指针
    // 修正：拼写错误（_onlint_user→_online_user）
    online_manager* _online_user;    
    // 棋盘数据（0=空，1=白棋，2=黑棋）
    std::vector<std::vector<int>> _board;

private:
    /**
     * 辅助函数：检测某方向是否形成五子连珠
     */
    bool five(int row, int col, int row_off, int col_off, int color) {
        int count = 1;  // 当前落子已算1颗
        int search_row = row + row_off;
        int search_col = col + col_off;

     
        while (search_row >= 0 && search_row < BOARD_ROW && 
               search_col >= 0 && search_col < BOARD_COL && 
               _board[search_row][search_col] == color) {
            count++;
            search_row += row_off;
            search_col += col_off;
        }

        // 修正：拼写错误（cor_off→col_off）
        search_row = row - row_off;
        search_col = col - col_off;
        while (search_row >= 0 && search_row < BOARD_ROW && 
               search_col >= 0 && search_col < BOARD_COL && 
               _board[search_row][search_col] == color) {
            count++;
            search_row -= row_off;
            search_col -= col_off;
        }

        return (count >= 5);
    }

    /**
     * 检测当前落子是否获胜
     */
    uint64_t check_win(int row, int col, int color) {
        
        if (five(row, col, 0, 1, color)   // 水平方向（左右）
         || five(row, col, 1, 0, color)   // 垂直方向（上下）
         || five(row, col, -1, 1, color)  // 正斜方向（左上→右下）
         || five(row, col, -1, -1, color))// 反斜方向（右上→左下）
        {
            // 三元运算符添加空格，提升可读性
            return color == CHESS_WHITE ? _white_id : _black_id;
        }
        return 0;  // 未获胜
    }

public:
    /**
     * 构造函数：初始化房间
   
     */
    room(uint64_t room_id, user_table* tb_user, online_manager* online_user)
        : _room_id(room_id),
          _statu(GAME_START),
          _player_count(0),
          _white_id(0),  // 初始化为无效ID（0）
          _black_id(0),  // 初始化为无效ID（0）
          _tb_user(tb_user),
          _online_user(online_user),
          _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0))  // 棋盘初始化（全空）
    {
        DLOG("%lu 房间创建完成", _room_id);
    }

    /**
     * 析构函数
     */
    ~room() {
        DLOG("%lu 房间已删除", _room_id);
    }

    /**
     * 获取房间ID
     */
    uint64_t id() {
        return _room_id;
    }

    /**
     * 获取房间状态
     */
    room_statu statu() {
        return _statu;
    }

    /**
     * 获取玩家数量
     */
    int player_count() {
        return _player_count;
    }

    /**
     * 添加白棋玩家
     */
    void add_white_user(uint64_t uid) {
        _white_id = uid;
        _player_count++;
    }

    /**
     * 添加黑棋玩家
     */
    void add_black_user(uint64_t uid) {
        _black_id = uid;
        _player_count++;
    }

    /**
     * 获取白棋玩家ID
     */
    uint64_t get_white_user() {
        return _white_id;
    }

    /**
     * 获取黑棋玩家ID
     */
    uint64_t get_black_user() {
        return _black_id;
    }

    /**
     * 处理下棋请求
    
     */
    Json::Value handle_chess(Json::Value& req) {
        Json::Value json_resp = req;
        // 补充：标记响应类型，便于前端识别
        json_resp["optype"] = "put_chess";

        // 1. 验证请求参数完整性（避免后续取值崩溃）
        if (!req.isMember("uid") || !req.isMember("row") || !req.isMember("col") || !req.isMember("room_id")) {
            json_resp["result"] = false;
            json_resp["reason"] = "请求参数缺失（需包含uid、row、col、room_id）";
            return json_resp;
        }

        // 2. 验证房间号匹配
        uint64_t req_room_id = req["room_id"].asUInt64();
        if (req_room_id != _room_id) {
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配（当前房间：" + std::to_string(_room_id) + "）";
            return json_resp;
        }

      
        uint64_t cur_uid = req["uid"].asUInt64();
        int chess_row = req["row"].asInt();
        int chess_col = req["col"].asInt();

        
        if (_online_user->is_in_game_room(_white_id) == false) {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，胜利";
            json_resp["winner"] = (Json::UInt64)_black_id;
            
            return json_resp;
        }
        if (_online_user->is_in_game_room(_black_id) == false) {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，胜利";
            json_resp["winner"] = (Json::UInt64)_white_id;
            return json_resp;
        }

        // 3. 验证落子位置是否为空
        if (_board[chess_row][chess_col] != 0) {
            json_resp["result"] = false;
            json_resp["reason"] = "当前位置已经被占用";
            // 修正：返回值类型错误
            return json_resp;
        }

        // 4. 落子（简化重复逻辑，提升可读性）
        int cur_color = cur_uid == _white_id ? CHESS_WHITE : CHESS_BLACK;
        _board[chess_row][chess_col] = cur_color;

        // 5. 检测胜负
        uint64_t winner_id = check_win(chess_row, chess_col, cur_color);
        if (winner_id != 0) {
            json_resp["reason"] = "五星连珠，胜利！";
        } else {
            json_resp["reason"] = "落子成功";
        }
        json_resp["result"] = true;
        json_resp["winner"] = (Json::UInt64)winner_id;
        return json_resp;
    }

    /**
     * 处理聊天请求
   
     */
    Json::Value handle_chat(Json::Value& req) {
        Json::Value json_resp = req;
        json_resp["optype"] = "chat";

        // 1. 验证请求参数完整性
        if (!req.isMember("room_id") || !req.isMember("uid") || !req.isMember("message")) {
            json_resp["result"] = false;
            json_resp["reason"] = "请求参数缺失（需包含room_id、uid、message）";
            return json_resp;
        }

        uint64_t room_id = req["room_id"].asUInt64();
        
        if (room_id != _room_id) {
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配";
            return json_resp;
        }

        // 2. 敏感词检测
        std::string msg = req["message"].asString();
        size_t pos = msg.find("垃圾");
        if (pos != std::string::npos) {
           
            json_resp["result"] = false;
            json_resp["reason"] = "发言违规";
            return json_resp;
        }

        json_resp["result"] = true;
        return json_resp;
    }


    void handle_exit(uint64_t uid) {
        Json::Value json_resp;
        if (_statu == GAME_START) {
            json_resp["optype"] = "put_chess";
            json_resp["result"] = true;
            json_resp["reason"] = "对方离开，胜利";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);
            
            broadcast(json_resp);
        }

        // 玩家数量减1（确保缩进正确）
        _player_count--;
        return;
    }

    void handle_request(Json::Value& req) {
        Json::Value json_resp;

        // 1. 验证房间号匹配
        if (!req.isMember("room_id") || !req.isMember("optype")) {
            json_resp["optype"] = req.isMember("optype") ? req["optype"].asString() : "unknown";
            json_resp["result"] = false;
            json_resp["reason"] = "请求参数缺失（需包含room_id、optype）";
           
            broadcast(json_resp);
            return;
        }

        uint64_t room_id = req["room_id"].asUInt64();
        if (room_id != _room_id) {
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不匹配";
            broadcast(json_resp);
            return;
        }

        // 2. 分请求类型处理
        std::string optype = req["optype"].asString();
      
        if (optype == "put_chess") {
            json_resp = handle_chess(req);
            if (json_resp["winner"].asUInt64() != 0) {
                uint64_t winner_id = json_resp["winner"].asUInt64();
                uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
               
                if (_tb_user != nullptr) {
                    _tb_user->win(winner_id);
                    _tb_user->lose(loser_id);
                }
                _statu = GAME_OVER;
            }
        }
        
        else if (optype == "chat") {
            json_resp = handle_chat(req);
        }
        else {
            json_resp["optype"] = optype;
            json_resp["result"] = false;
            json_resp["reason"] = "未知请求";
        }

       
        broadcast(json_resp);
        return;
    }

    /**
     * 广播消息给房间内所有玩家
     *
     */
    void broadcast(Json::Value& rsp) {
        std::string body;
        
        if (!json_util::serialize(rsp, body)) {
            ELOG("JSON序列化失败，广播消息发送失败");
            return;
        }

        
        wsserver_t::connection_ptr wconn = _online_user->get_conn_from_room(_white_id);
        if (wconn.get() != nullptr) {
            wconn->send(body);
        }

        wsserver_t::connection_ptr bconn = _online_user->get_conn_from_room(_black_id);
        if (bconn.get() != nullptr) {
            bconn->send(body);
        }
        return;
    }
};

// 房间智能指针类型别名
using room_ptr = std::shared_ptr<room>;

class room_manager {
private:
    uint64_t _next_rid;                  // 下一个房间ID（自增生成）
    std::mutex _mutex;                   // 互斥锁，保证线程安全
    user_table* _tb_user;                // 用户数据库操作指针
    online_manager* _online_user;        // 在线用户管理指针
    std::unordered_map<uint64_t, room_ptr> _rooms;  // 房间ID -> 房间智能指针
    std::unordered_map<uint64_t, uint64_t> _users;  // 用户ID -> 所在房间ID

public:
    /**
     * 构造函数：初始化房间管理器
     * @param ut：用户数据库操作实例
     * @param om：在线用户管理实例
     */
    room_manager(user_table* ut, online_manager* om)
        : _next_rid(1), _tb_user(ut), _online_user(om)  
    {
        DLOG("房间管理初始化完毕");
    }

    /**
     * 析构函数：释放资源
     */
    ~room_manager() {
        DLOG("房间管理销毁");
    }

    /**
     * 创建房间，将两个用户匹配到房间中
     * @param uid1：玩家1（白棋）
     * @param uid2：玩家2（黑棋）
     * @return 成功返回房间智能指针，失败返回空指针
     */
    room_ptr create_room(uint64_t uid1, uint64_t uid2) {
        // 1. 校验两个用户是否都在游戏大厅（防止重复进入房间）
        if (!_online_user->is_in_game_hall(uid1)) { 
            DLOG("用户：%lu 不在大厅中，创建房间失败", uid1);
            return nullptr;  
        }
        if (!_online_user->is_in_game_hall(uid2)) {
            DLOG("用户：%lu 不在大厅中，创建房间失败", uid2);
            return nullptr;
        }

        // 2. 加锁创建房间（保证线程安全）
        std::unique_lock<std::mutex> lock(_mutex);

        // 3. 创建房间对象并分配玩家
        room_ptr rp(new room(_next_rid, _tb_user, _online_user));
        rp->add_white_user(uid1);  // uid1作为白棋玩家
        rp->add_black_user(uid2);  // uid2作为黑棋玩家

        // 4. 记录房间和用户的关联关系
        _rooms.insert(std::make_pair(_next_rid, rp)); 
        _users.insert(std::make_pair(uid1, _next_rid));  
        _users.insert(std::make_pair(uid2, _next_rid));

        // 5. 更新房间ID计数器
        uint64_t new_rid = _next_rid;  // 保存当前房间ID（返回前自增）
        _next_rid++;

        DLOG("创建房间成功，房间ID：%lu，玩家1：%lu（白棋），玩家2：%lu（黑棋）", new_rid, uid1, uid2);
        return rp;
    }

    /**
     * 通过房间ID获取房间信息
     * @param rid：房间ID
     * @return 成功返回房间智能指针，失败返回空指针
     */
    room_ptr get_room_by_rid(uint64_t rid) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _rooms.find(rid);
        if (it == _rooms.end()) {  
            DLOG("房间ID：%lu 不存在", rid);
            return nullptr;
        }
        return it->second;
    }

    /**
     * 通过用户ID获取所在房间信息
     * @param uid：用户ID
     * @return 成功返回房间智能指针，失败返回空指针
     */
    room_ptr get_room_by_uid(uint64_t uid) {  
        std::unique_lock<std::mutex> lock(_mutex);

        // 1. 先通过用户ID查找房间ID
        auto uit = _users.find(uid);
        if (uit == _users.end()) {  
            DLOG("用户：%lu 不在任何房间中", uid);
            return nullptr;
        }
        uint64_t rid = uit->second;

        // 2. 再通过房间ID查找房间
        auto rit = _rooms.find(rid);
        if (rit == _rooms.end()) {
            DLOG("用户：%lu 关联的房间ID：%lu 不存在", uid, rid);
            return nullptr;
        }
        return rit->second;
    }

    /* 通过房间ID删除房间*/
    void remove_room(uint64_t rid) {
        // 1. 先检查房间是否存在
        room_ptr rp = get_room_by_rid(rid);
        if (!rp) {  // 等价于 rp.get() == nullptr
            DLOG("删除房间失败，房间ID：%lu 不存在", rid);
            return;
        }

        // 2. 加锁删除关联关系
        std::unique_lock<std::mutex> lock(_mutex);

        // 3. 移除房间内所有用户的关联
        uint64_t uid1 = rp->get_white_user();
        uint64_t uid2 = rp->get_black_user();
        _users.erase(uid1);
        _users.erase(uid2);

        // 4. 从房间列表中删除（智能指针引用计数减1，自动释放房间资源）
        _rooms.erase(rid);

        DLOG("删除房间成功，房间ID：%lu", rid);
    }

    /**
     * 移除房间中的指定用户，若房间为空则销毁房间
     * @param uid：要移除的用户ID
     */
    void remove_room_user(uint64_t uid) {
        // 1. 查找用户所在房间
        room_ptr rp = get_room_by_uid(uid);
        if (!rp) {
            DLOG("移除用户失败，用户：%lu 不在任何房间中", uid);
            return;
        }

        // 2. 通知房间处理用户退出逻辑（如判定胜负）
        rp->handle_exit(uid);

        // 3. 从用户-房间关联表中移除该用户
        std::unique_lock<std::mutex> lock(_mutex);
        _users.erase(uid);

        // 4. 若房间内已无玩家，销毁房间
        if (rp->player_count() == 0) {
            remove_room(rp->id());
        } else {
            DLOG("用户：%lu 已退出房间，当前房间剩余玩家数：%d", uid, rp->player_count());
        }
    }
};

#endif
